# api/auth.py
from fastapi import APIRouter, Depends, HTTPException
from jose import jwt, JWTError
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from controllers.console.deps import oauth2_scheme, require_role
from core.config import settings
from core.logging_config import logger
from core.security import verify_password, create_access_token, hash_password
from db.session import get_db
from extension.ext_redis import get_redis
from models.role import Role
from models.user import User
from schemas.user import Token, UserOut
from schemas.user import UserCreate
from redis.asyncio import Redis

from services.account_service import AccountService
from tasks.test import say_hello

router = APIRouter(tags=["auth"])


@router.post("/register", response_model=UserOut)
async def register(user_in: UserCreate, _: User = Depends(require_role("admin")), db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User).where(User.username == user_in.username))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Username already exists")

    role = None
    if user_in.role_id:
        role = await db.get(Role, user_in.role_id)
        if not role:
            raise HTTPException(status_code=404, detail="Role not found")

    user = User(
        username=user_in.username,
        hashed_password=hash_password(user_in.password),
        role=role
    )
    db.add(user)
    await db.commit()
    await db.refresh(user)
    return user


@router.post("/install", response_model=UserOut)
async def register(user_in: UserCreate, db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Root user already exists")

    role = None
    if user_in.role_id:
        role = await db.get(Role, user_in.role_id)
        if not role:
            raise HTTPException(status_code=404, detail="Role not found")

    user = User(
        username=user_in.username,
        hashed_password=hash_password(user_in.password),
        role=role
    )
    db.add(user)
    await db.commit()
    await db.refresh(user)
    return user


@router.post("/login", response_model=Token)
async def login(user_in: UserCreate, db: AsyncSession = Depends(get_db), redis: Redis = Depends(get_redis)):
    result = await db.execute(select(User).where(User.username == user_in.username))
    user = result.scalar_one_or_none()
    if not user or not verify_password(user_in.password, user.hashed_password):
        logger.warning(f"Login failed for username={user_in.username}")
        raise HTTPException(status_code=400, detail="Invalid username or password")

    token = create_access_token({"sub": str(user.id)})
    logger.info(f"Login successful for username={user_in.username}")
    await redis.setex(AccountService.get_access_key(token, user.id), settings.ACCESS_TOKEN_EXPIRE_MINUTES, 1)
    return {"access_token": token, "token_type": "bearer"}


@router.get("/logout", response_model=dict)
async def logout(token: str = Depends(oauth2_scheme), redis: Redis = Depends(get_redis)):
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
        user_id: str = payload.get("sub")
        if user_id is None:
            raise HTTPException(status_code=401, detail="Invalid token")
        # data = redis.get(f'{token}:{user_id}')
        # if data:
        await redis.delete(AccountService.get_access_key(token, user_id))
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

    return {"message": "success"}

@router.get("/healthcheck", response_model=dict)
async def healthcheck():
    say_hello.delay()
    return {"status": "ok"}